/* Class Name: iFulfillQueryHandler
* Author: Accenture IDC
* Date: 014-July-2011
* Requirement/Project Name: ifulfill
* Requirement/Project Description: Handles the processing on Query and Query requests
**/

public class iFulfillQueryHandler
{

    /*populate the email template id based on query reason to auto-populate email service template*/
    public static void updateEmailTemplate(list<Queries__c> querylist)
    {
        //Get the instance of Custom Setting object;
        Map<String,iFulfill__c> queryTemplateMap = iFulfill__c.getAll();   
        String qCode;
        String trimQCode;
        String apiKeyQCode;

        for(queries__C q: querylist)
        { 
            qCode=q.Query_Reason__c;
             try
             {
                 trimQCode = qcode.substring(0,4);
                 boolean isTemplate = queryTemplateMap.containsKey(trimQCode);//get the template for corresponding reason code    
                 // Check if query code has associated template else update it empty string
                 if(isTemplate)
                 {
                     String TempId = iFulfill__c.getValues(trimQCode).Template_Id__C;
                     q.Email_Template_Id__c = TempId ;
                 }
                 else
                 {
                     q.Email_Template_Id__c = '';
                 }         
          }
          catch(Exception e)
          {
              GeneralConstants.mailAnyExceptionToMe('iFulfillQueryHandler','updateEmailTemplate',e);
           }     
        }
    }

    /** populate snapshot/auto fields on Query**/
    public static void updateAutoFields(list<Queries__c> querylist)
    {
        Map<id,String> queryUdac = new Map<id,String>(); 
        Set<Id> queryReqId =  new Set<ID>();
        list<Queries__c> qlist = new list<Queries__c>();    
        for ( Queries__c obj :querylist)
        {
           queryReqId.add(obj.Query_Request_ID__c);
        }
        if(querylist.size() > 0)
        {
            list<Query_Request__c> queryReqList  = [select id,UDAC_Description__c  from Query_Request__c where id in :queryReqId ];
            
            // Check  if query has returned any rows
            
            if(queryReqList.size() > 0 )
            {
                for(Query_Request__c qreq :queryReqList   )
                {
                      queryUdac.put(qreq.id,qreq.UDAC_Description__c );
                }
            }
            for(Queries__c q  : querylist)
            {
                q.UDAC_Description__c = queryUdac.get(q.Query_Request_ID__c);
            }
       } 
    }   

     /*
      *
      * update snapshot fields on FI
      **/
    public static void updateOwnerAndFISnapshot(list<Query_Request__c> querylist)
    {
        List<Query_Request__c> qlist = new List<Query_Request__c>();  
        Set<id> InProgressReq = new Set<Id>();    
        Set<id> reqIds = new Set<id>();     
        for(Query_Request__c q: [select id,createdbyid,Request_Reason__c,Query_Type__c,Fulfillment_Item__r.UDAC_Description__c,request_status__c,Fulfillment_Item__c, Fulfillment_Item__r.Current_Function_Name__c,Fulfillment_Item__r.Current_Task_Name__c,Fulfillment_Item__r.status__c,
                                Fulfillment_Item__r.Region__c, Fulfillment_Item__r.Workflow_Coordinator__c
                                from Query_Request__c where id in :Querylist])
        {
            if(q.Query_Type__c == IfullfillTextConstant.QUERY_INIT_TYPE)
            {     
                q.Request_Reason__c = IfullfillTextConstant.QUERY_INIT_REASON;
            }   
            //auto snapshot fields carried over from FI
            q.Current_Function__c = q.Fulfillment_Item__r.Current_Function_Name__c;
            q.Current_Task__c = q.Fulfillment_Item__r.Current_Task_Name__c;
            //q.Workflow_Status__c = q.Fulfillment_Item__r.status__c;  
            q.UDAC_Description__c = q.Fulfillment_Item__r.UDAC_Description__c;
            qlist.add(q);   
        }
        try
        {
            update qlist;
        }
        catch(Exception e)
        {
              GeneralConstants.mailAnyExceptionToMe('iFulfillQueryHandler','updateEmailTemplate',e);
        } 
    }


    /**update FI status based on Query Request status**/
    public static void updateFIStatus(boolean isInsert, list<Query_Request__c>reqIds)
    {
        list<Fullfilment_Item__c> FIList = new list<Fullfilment_Item__c>();
        set<id> FItemIds = new Set<Id>();
        set<id> InQueryFItemIds = new Set<Id>();

        for(Query_Request__c QR : reqIds)
        {
            FItemIds.add(QR.Fulfillment_Item__c); 
        }
    
        if (!isInsert)
        {
            for(Query_Request__c qrList : [select id,Fulfillment_Item__c from Query_Request__c
                                           where (request_status__c = :IfullfillTextConstant.QUERY_OPEN_STATUS or request_status__c = :IfullfillTextConstant.QUERY_PROGRESS_STATUS)
                                                and  Fulfillment_Item__c in :FItemIds and id not in :reqIds])
            {
                InQueryFItemIds.add(qrList.Fulfillment_Item__c); 
            
            }
       
        
            for(Fullfilment_Item__c FI :[select status__c from Fullfilment_Item__c where id in :FItemIds and id not in :InQueryFItemIds and status__c != :IfullfillTextConstant.FI_WORKFLOW_OUTED_STATUS ])
            {
                FI.status__c = IfullfillTextConstant.FI_WORKFLOW_PROGRESS_STATUS;
                FIList.add(FI);
            }
        }
    
        if(isInsert)
            for(Fullfilment_Item__c FI  :[select status__c from Fullfilment_Item__c where id in :FItemIds] )
            {
                FI.status__c = IfullfillTextConstant.FI_WORKFLOW_QUERY_STATUS;
                FIList.add(FI);        
            }
           
        try
        {
            update FIList;
        }
        catch(DMLException e)
        {
              GeneralConstants.mailAnyExceptionToMe('iFulfillQueryHandler','updateFIStatus',e);
        }
    }

    /**Calculate total no of queries open/closed and updates request status based on that**/    
    public static void updateReqStatus(list<Queries__c> querylist,set<id> ReqIds)
    {
        set<id> InProgressReq = new Set<Id>();
        set<id> closedReq = new Set<Id>();
        list<Query_Request__c> updateReqList = new list<Query_Request__c>(); 
        for(queries__c InProgressQs : [select Query_Request_ID__c from queries__c
                                         where (Query_Status__c = :IfullfillTextConstant.QUERY_OPEN_STATUS or Query_Status__c = :IfullfillTextConstant.QUERY_PROGRESS_STATUS)
                                            and Query_Request_ID__c in :ReqIds and id not in :querylist])
        {
               InProgressReq.add(InProgressQs.Query_Request_ID__c); 
        }
        for(queries__c Q : querylist){    
            if(!InProgressReq.Contains(Q.Query_Request_ID__c)){
                closedReq.add(Q.Query_Request_ID__c);
            }
         }
         
         for(Query_Request__c Req : [select Request_Status__c from Query_Request__c where id in :closedReq])
         {            
             Req.Request_Status__c = IfullfillTextConstant.QUERY_CLOSED_STATUS;
             updateReqList.add(Req); 
         }
         try
         {
             Update  updateReqList;
         }
         catch(dmlException e)
         {
             GeneralConstants.mailAnyExceptionToMe('iFulfillQueryHandler','updateReqStatus',e);
         }
      }
    

 
    /** Calculates Query SLA***/
    public static void updateQuerySla(list<Queries__c> querylist)
    { 
        Integer count  = 0;   
        Set<String> fiName = new Set<String>();
        Map<String,ID> fiNameMap  = new Map<String,ID>();
        Map<String, Integer> fiIDCountMap =  new Map<String,Integer>();
        List<Fullfilment_Item__c> fiList  = null;
        ListViewIds__c listVId = ListViewIds__c.getInstance();
        List<AggregateResult> aggResultList = null;
        for(Queries__c query :querylist )
        {
            fiName.add(query.Fulfillment_ID1__c);
        }
        fiList = [Select id , name from Fullfilment_Item__c where name in :fiName]; 
        
        for(Fullfilment_Item__c fiObj : fiList )
        {
            fiNameMap.put(fiObj.Name,fiObj.id);
        }
        aggResultList  = [ select count(id) noOfRec,Query_Request_ID__r.Fulfillment_Item__c fiID from Queries__c where Query_Request_ID__r.Fulfillment_Item__r.name   in :fiName group by Query_Request_ID__r.Fulfillment_Item__c];
        
        for(AggregateResult aggResultObj : aggResultList )
        {
            ID tempID  = String.valueof(aggResultObj.get('fiID'));
            Integer noOfrec = Integer.valueof(aggResultObj.get('noOfRec'));
            fiIDCountMap.put(tempID,noOfrec );
        }
        
        for(Queries__c query :querylist )
        {
              // Update Query SLA based on FI region.
              count =0;
              if(query.Region__c != null &&
              query.Region__c.equalsIgnoreCase(IfullfillTextConstant.FI_WORKFLOW_IE_REG) )
              {
                        query.Query_SLA__c = listVId.IRQuery_SLA__c ;
              }
              else if(query.Region__c != null &&
                       query.Region__c.equalsIgnoreCase(IfullfillTextConstant.FI_WORKFLOW_IW_REG) )
              {
                        query.Query_SLA__c = listVId.IRQuery_SLA__c ;
              }
              else if(query.Region__c != null &&
                       query.Region__c.equalsIgnoreCase(IfullfillTextConstant.FI_WORKFLOW_OOR_REG) )
              {
                         query.Query_SLA__c = listVId.OORQuery_SLA__c ;
              }
              
              // Check if query has already created for FI the Change query SLA 2
               
              if(query.Query_Request_Type__c !=null && 
                                  query.Query_Request_Type__c.equalsIgnoreCase(IfullfillTextConstant.QUERY_MID_TYPE ) && 
                                  (query.Region__c != null && !query.Region__c.equalsIgnoreCase(IfullfillTextConstant.FI_WORKFLOW_OOR_REG)))
              {                
                  
                  
                  count =   fiIDCountMap.keySet().contains(fiNameMap.get(query.Fulfillment_ID1__c))?
                                  fiIDCountMap.get(fiNameMap.get(query.Fulfillment_ID1__c)): 0;                
                  if(count >  0)
                  {
                     query.Query_SLA__c = listVId.Query_SLA__c ;
                  }
              }
           }  
        }

    /*
    * This Method will fetch business days count and weekend days count between Start Date and Query SLA Days.
    * Add businessdays+ weekend days to get the final Expiration Date.
    */
   public static Datetime addBussinessDays(Datetime startDate, Integer querySLADays)
    {        
       Integer weekEndCount=0;
       Integer weekdaysCount=0;
       Integer count=0;
       Datetime tempDate =startDate; 
       Datetime endDate = startDate.addDays(querySLADays);
        
        if(startDate.format('E') == 'Sat'||startDate.format('E') == 'Sun'){
            System.debug('startDate '+startDate.format('E'));
            startDate= startDate.addDays(1);   
            count =count+1;         
        }
        while (startDate<= endDate)
        {
        
           System.debug('start format'+startDate.format('E'));

          if (startDate.format('E') == 'Sat' | startDate.format('E') == 'Sun')
            {
               System.debug('start format'+startDate.format('E'));
               weekEndCount = weekEndCount+ 1;
            }else if(count >0){
                System.debug('startDate ....'+startDate+'format....'+startDate.format('E')+'weekday count'+weekdaysCount);
                weekdaysCount= weekdaysCount+1;                
            }
            if(endDate == startDate && weekdaysCount !=querySLADays){
              endDate =endDate.addDays(1);   
              System.debug('After end date'+endDate.format('E'));
            }
            startDate= startDate.addDays(1);
            count =count+1;
            System.debug('After Start day change'+startDate.format('E'));
        }
        System.debug('iCount'+weekEndCount+'weekdays '+weekdaysCount);

        Integer totalCount=weekEndCount+weekdaysCount;
        System.debug('temp date'+tempDate+'start date'+startDate);
        
        return tempDate.addDays(totalCount);
        
     }
       
    /*
    * This method will populate Expiration Date. 
    * If the External Establish Date is not null then Exp Date= External Establish Date+Query SLA (business days)else Requested Date+Query SLA(business Days). 
    */
    public static void populateExpirationDate(list<Queries__c> querylist){
    
            for(Queries__c query :querylist)
            {
                 System.debug('External_Establish_Date__c --->'+query.External_Establish_Date__c+'Requested_Date__c date--->'+query.Requested_Date__c);
             
                if(query.External_Establish_Date__c !=null && query.Query_SLA__c !=null){
                    query.Exp_Date__c= addBussinessDays(query.External_Establish_Date__c,query.Query_SLA__c.intValue());
                }else if(query.External_Establish_Date__c ==null && query.Query_SLA__c !=null) {
                      query.Exp_Date__c= addBussinessDays(query.Requested_Date__c,query.Query_SLA__c.intValue());
                }      
            }
    }
    
    

    /*
     *
     * update Query Request Owner if WorkFLow Coordinator is assigned to FI
     **/
    public static void updateQROwnerForOOR(list<Query_Request__c>reqIds)
    {
        list<Fullfilment_Item__c> fiList = new list<Fullfilment_Item__c>();
        Map <ID,Fullfilment_Item__c >  fiMap =   new Map <ID,Fullfilment_Item__c > ();
        set<id> FItemIds = new Set<Id>();
        set<id> InQueryFItemIds = new Set<Id>();
    
        for(Query_Request__c QR : reqIds)
        {
            FItemIds.add(QR.Fulfillment_Item__c); 
        }
    
        fiList = [select Workflow_Coordinator__c ,Region__c from Fullfilment_Item__c where id in :FItemIds ];
    
        for(Fullfilment_Item__c fiObj :fiList)
        {
            fiMap.put(fiObj.id ,fiObj);
        }
    
        for(Query_Request__c qryReq  : reqIds)
        {
            if(fiMap.containsKey(qryReq.Fulfillment_Item__c))
            {
               Fullfilment_Item__c tempFi  = fiMap.get(qryReq.Fulfillment_Item__c); 
               
               // Change query owner to Workflow Coordinator if FI has assigned to Workflow Coordinator for Mid-Fulfillment query type.
                
               if(tempFi.Workflow_Coordinator__c != null  &&  tempFi.Region__c== IfullfillTextConstant.FI_WORKFLOW_OOR_REG  &&  qryReq.Query_Type__c== IfullfillTextConstant.QUERY_MID_TYPE)
               {
                   qryReq.ownerID = tempFi.Workflow_Coordinator__c;
                   qryReq.Request_Status__c = IfullfillTextConstant.QUERY_PROGRESS_STATUS ; 
               }      
            }
       }
    
    }      
}